package xin.huangyan.accessibilityapp;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;

import androidx.annotation.RequiresApi;

import java.util.List;

import xin.huangyan.accessibilityapp.internet.SocketManager;
import xin.huangyan.accessibilityapp.utils.HLog;


public class MyAccessibilityService extends AccessibilityService {
    private static MyAccessibilityService service;
    private Handler handler = new Handler(Looper.getMainLooper());
    private FindViewCallback findViewCallback;

    public static MyAccessibilityService getService() {
        return service;
    }

    public void setFindViewCallback(FindViewCallback findViewCallback) {
        this.findViewCallback = findViewCallback;
    }

    //初始化
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        HLog.i( "AccessibilityService 已开启");
        service = this;
    }
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        try {
//            printEvent(event);
            if (findViewCallback != null) {
                AccessibilityNodeInfo nodeInfo = null;
                if (!TextUtils.isEmpty(findViewCallback.id)) {
                    nodeInfo = findViewByID(findViewCallback.id, findViewCallback.className);
                } else if (!TextUtils.isEmpty(findViewCallback.text)) {
                    nodeInfo = findViewByText(findViewCallback.text, findViewCallback.fuzzy);
                }
                if (nodeInfo != null) {
                    findViewCallback.result(nodeInfo);
                    findViewCallback = null;
                }
            }
            if ("com.tencent.mm".equals(event.getPackageName())
                    && AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED == event.getEventType()) {
                SocketManager.getInstance().sendMsg((String) event.getText().get(0));
            }
        } catch (Exception e) {
            HLog.i("onAccessibilityEvent Exception:" + e);
        }
    }

    @Override
    public void onInterrupt() {
        HLog.i("onInterrupt");
    }
    /**
     * 好像只有外部输入设备才会调用,音量按键之类的（虚拟键盘没用）
     */
    @Override
    protected boolean onKeyEvent(KeyEvent event) {
        HLog.i("onKeyEvent" + event);
        return super.onKeyEvent(event);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        HLog.i("AccessibilityService 已关闭");
        service = null;
    }

    /**
     * 查找对应ID的View
     *
     * @param id id
     * @return View
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public AccessibilityNodeInfo findViewByID(String id, String className) {
        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
        if (accessibilityNodeInfo == null) {
            return null;
        }
        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);
        if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
                if (nodeInfo != null) {
                    if (TextUtils.isEmpty(className)) {
                        return nodeInfo;
                    } else if (className.equals(nodeInfo.getClassName())) {
                        return nodeInfo;
                    }
                }
            }
        }
        return null;
    }
    /**
     * 查找对应文本的View
     * @param text      text
     * @param fuzzy 是否模糊搜索
     * @return View
     */
    public AccessibilityNodeInfo findViewByText(String text, boolean fuzzy) {
        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();
        if (accessibilityNodeInfo == null) {
            return null;
        }
        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);
        if (nodeInfoList != null && !nodeInfoList.isEmpty()) {
            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {
                if (nodeInfo != null) {
                    if (fuzzy) {
                        return nodeInfo;
                    } else if (nodeInfo.getText() != null && text.equals(nodeInfo.getText().toString())) {
                        return nodeInfo;
                    }
                }
            }
        }
        return null;
    }
    /**
     * 模拟点击事件
     *
     * @param nodeInfo nodeInfo
     */
    public void performViewClick(AccessibilityNodeInfo nodeInfo) {
        if (nodeInfo == null) {
            return;
        }
        while (nodeInfo != null) {
            if (nodeInfo.isClickable()) {
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                HLog.i("performViewClick");
                break;
            }
            nodeInfo = nodeInfo.getParent();
        }
    }
    /**
     * 触摸指定位置，实现touch、click或long click，有些应用click方法被和谐了，可以使用此方法
     * 注意7.0以上的手机才有此方法，请确保运行在7.0手机上
     */
    @RequiresApi(24)
    public void dispatchTouchGesture(AccessibilityNodeInfo nodeInfo, int duration) {
        if (nodeInfo == null) {
            return;
        }
        Rect absXY = new Rect();
        nodeInfo.getBoundsInScreen(absXY);
        //点击控件正中间位置
        int x = absXY.left + (absXY.right - absXY.left) / 2;
        int y = absXY.top + (absXY.bottom - absXY.top) / 2;
        Path path = new Path();
        path.moveTo(x - 1, y - 1);
        path.lineTo(x, y - 1);
        path.lineTo(x, y);
        path.lineTo(x - 1, y);
        dispatchGesture(new GestureDescription.Builder().addStroke(new GestureDescription.StrokeDescription
                (path, 0, duration)).build(), null, null);
    }
    /**
     * 模拟输入
     *
     * @param nodeInfo nodeInfo
     * @param text     text
     */
    public void inputText(AccessibilityNodeInfo nodeInfo, String text) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Bundle arguments = new Bundle();
            arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
            nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
            ClipData clip = ClipData.newPlainText("label", text);
            clipboard.setPrimaryClip(clip);
            nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
            nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);
        }
    }
    /**
     * 模拟返回操作
     */
    public void performBackClick() {
        performGlobalAction(GLOBAL_ACTION_BACK);
    }

    public void printEvent(AccessibilityEvent event){
        HLog.i("onAccessibilityEvent packageName:" + event.getPackageName());
        HLog.i("onAccessibilityEvent getAction:"+event.getAction());
        switch (event.getEventType()) {
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                HLog.i("onAccessibilityEvent event:点击");
                break;
            case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                HLog.i("onAccessibilityEvent event:长按");
                break;
            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                HLog.i("onAccessibilityEvent event:文本改变");
                break;
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                HLog.i("onAccessibilityEvent event:界面改变");
                break;
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                HLog.i("onAccessibilityEvent event:通知栏改变");
                break;
            case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
                HLog.i("onAccessibilityEvent event:系统窗口的时间改变");
                break;
            default:
                HLog.i("onAccessibilityEvent event:"+event.getEventType());
        }
        HLog.i("onAccessibilityEvent getText:"+event.getText());
    }
}
